#pragma once

#include "njm_entity.hpp"
#include "njm_component.hpp"
#include "njm_system.hpp"

#include "njm_entity_mgr.hpp"
#include "njm_system_mgr.hpp"
#include "njm_component_array.hpp"
#include "njm_component_mgr.hpp"

#include <vector>
#include <array>
#include <memory>
#include <cassert>
#include <iostream>

namespace njm
{
    /**
     * @brief ECS (Entity Component System, aka Coordinator) : 实体组件系统
     *  Entity: 实体
     *  Component: 组件
     *  System: 系统
     *  EntityManager: 实体管理器
     *  ComponentManager: 组件管理器
     *  SystemManager: 系统管理器
     *  ComponentArray: 组件数组
     *  Signature: 组件签名
     */
    class Coordinator
    {
    public:
        Coordinator();
        ~Coordinator();
        void Init();
        void Clear();
        void Update(float deltaTime);

        // Entity 相关方法
        Entity CreateEntity();
        std::vector<Entity> CreateEntities(int count);
        void DestroyEntity(Entity entity);

        // Component 相关方法
        template <typename T>
        void RegisterComponent()
        {
            mComponentManager->RegisterComponent<T>();
        }
        template <typename T>
        ComponentType GetComponentType()
        {
            return mComponentManager->GetComponentType<T>();
        }
        template <typename T>
        Signature GetComponentSignature()
        {
            return mComponentManager->GetComponentSignature<T>();
        }
        template <typename T>
        const char *GetComponentName()
        {
            return mComponentManager->GetComponentName<T>();
        }

        template <typename T>
        void AddComponent(Entity entity, T component)
        {
            mComponentManager->AddComponent<T>(entity, component);

            Signature signature = mEntityManager->GetSignature(entity);
            signature.set(mComponentManager->GetComponentType<T>(), true);
            mEntityManager->SetSignature(entity, signature);

            mSystemManager->EntitySignatureChanged(entity, signature);
        }

        template <typename T>
        void RemoveComponent(Entity entity)
        {
            mComponentManager->RemoveComponent<T>(entity);

            Signature signature = mEntityManager->GetSignature(entity);
            signature.set(mComponentManager->GetComponentType<T>(), false);
            mEntityManager->SetSignature(entity, signature);

            mSystemManager->EntitySignatureChanged(entity, signature);
        }

        template <typename T>
        T &GetComponent(Entity entity)
        {
            return mComponentManager->GetComponent<T>(entity);
        }
        
        template <typename T>
        void SetComponent(Entity entity, T component)
        {
            mComponentManager->SetComponent<T>(entity, component);
        }

        // System 相关方法
        template <typename T>
        std::shared_ptr<T> RegisterSystem()
        {
            return mSystemManager->RegisterSystem<T>();
        }

        template <typename T>
        void SetSystemSignature(Signature signature)
        {
            mSystemManager->SetSignature<T>(signature);
        }

        template <typename T>
        std::shared_ptr<T> GetSystem()
        {
            return mSystemManager->GetSystem<T>();
        }

        template <typename T>
        void AddEntityToSystem(Entity entity)
        {
            if (mEntityManager->HasSignature(entity, mSystemManager->GetSignature<T>()))
            {
                mSystemManager->AddEntityToSystem<T>(entity);
            }
        }

        template <typename T>
        void RemoveEntityFromSystem(Entity entity)
        {
            if (mEntityManager->HasSignature(entity, mSystemManager->GetSignature<T>()))
            {
                mSystemManager->RemoveEntityFromSystem<T>(entity);
            }
        }

    private:
        std::unique_ptr<ComponentManager> mComponentManager;
        std::unique_ptr<EntityManager> mEntityManager;
        std::unique_ptr<SystemManager> mSystemManager;
    };
    using ECS = Coordinator;
}
// #include <njm_ecs.tpp>